package git

import (
	"bytes"
	"compress/zlib"
	"encoding/hex"
	"testing"

	"github.com/stretchr/testify/assert"
)

const fixtureCommit = `tree 0063878ef424196f8c03563bb7192ddd75a943cd
parent dbd0251d6dfd9c5ca7843164f9a40f2efd334aab
author Yurii Rashkovskii <yrashk@gmail.com> 1400915287 +0800
committer Yurii Rashkovskii <yrashk@gmail.com> 1400915287 +0800

Commit object should support multiple parents
`

func TestHash(t *testing.T) {
	c := &Commit{}
	c.SetBytes([]byte(fixtureCommit))
	assert.Equal(t, hex.EncodeToString(c.Hash()), "03a95d185ca6adeac9a1b4e0d2aaea9b208b3bf4")
}

const fixtureMultiparentCommit = `tree 69218c749588a7147b99ff45bf7d18db1bb126e8
parent d3030ad8f6ad49e5ad69a2842f06940c60f9db6f
parent d3030ad8f6ad49e5ad69a2842f06940c60f9db61
author Yurii Rashkovskii <yrashk@gmail.com> 1400767572 +0800
committer Yurii Rashkovskii <yrashk@gmail.com> 1400767572 +0800

Add HACKING.md`

func TestCommitDecode(t *testing.T) {
	c := &Commit{}
	c.SetBytes([]byte(fixtureMultiparentCommit))
	assert.Equal(t, hex.EncodeToString(c.Tree), "69218c749588a7147b99ff45bf7d18db1bb126e8")
	assert.Equal(t, hex.EncodeToString(c.Parents[0]), "d3030ad8f6ad49e5ad69a2842f06940c60f9db6f")
	assert.Equal(t, hex.EncodeToString(c.Parents[1]), "d3030ad8f6ad49e5ad69a2842f06940c60f9db61")
	assert.Equal(t, c.Author, "Yurii Rashkovskii <yrashk@gmail.com> 1400767572 +0800")
	assert.Equal(t, c.Committer, "Yurii Rashkovskii <yrashk@gmail.com> 1400767572 +0800")
	assert.Equal(t, c.Message, "Add HACKING.md")
}

var fixtureTree = []byte{
	0x74, 0x72, 0x65, 0x65, 0x20, 0x36, 0x34, 0x38, 0x00, 0x31, 0x30, 0x30,
	0x36, 0x34, 0x34, 0x20, 0x2e, 0x67, 0x69, 0x74, 0x69, 0x67, 0x6e, 0x6f,
	0x72, 0x65, 0x00, 0x03, 0x7f, 0x24, 0xbc, 0xd0, 0xf2, 0x94, 0x33, 0x1e,
	0x58, 0xb3, 0xdc, 0x4d, 0xa8, 0xa9, 0xb3, 0xc5, 0x36, 0x91, 0x49, 0x31,
	0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x47, 0x6f, 0x64, 0x65, 0x70, 0x73,
	0x00, 0xfd, 0xee, 0x6d, 0xb6, 0x72, 0xc2, 0x40, 0x1b, 0x6e, 0x02, 0x7f,
	0xc5, 0xf6, 0x2f, 0x43, 0x71, 0xc5, 0x1a, 0x27, 0x26, 0x31, 0x30, 0x30,
	0x36, 0x34, 0x34, 0x20, 0x48, 0x41, 0x43, 0x4b, 0x49, 0x4e, 0x47, 0x2e,
	0x6d, 0x64, 0x00, 0xa0, 0x85, 0x8e, 0x68, 0x0d, 0xb6, 0x68, 0xde, 0x82,
	0x63, 0x5e, 0xb4, 0x86, 0x90, 0xd7, 0x93, 0x3d, 0xa0, 0x28, 0x14, 0x31,
	0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53,
	0x45, 0x00, 0x21, 0x57, 0x01, 0xc6, 0x6d, 0x86, 0x23, 0xc0, 0xb6, 0x6f,
	0x1b, 0xb4, 0xa7, 0x8f, 0xe5, 0xf4, 0xe1, 0xd5, 0xe0, 0x3a, 0x31, 0x30,
	0x30, 0x36, 0x34, 0x34, 0x20, 0x4d, 0x61, 0x6b, 0x65, 0x66, 0x69, 0x6c,
	0x65, 0x00, 0x29, 0x25, 0x81, 0xf3, 0x09, 0x7a, 0xa4, 0x3e, 0xef, 0x24,
	0x9e, 0x3b, 0xf5, 0xf1, 0x1d, 0xdd, 0xf4, 0xd9, 0x0d, 0x29, 0x31, 0x30,
	0x30, 0x36, 0x34, 0x34, 0x20, 0x52, 0x45, 0x41, 0x44, 0x4d, 0x45, 0x2e,
	0x6d, 0x64, 0x00, 0xec, 0x6e, 0x47, 0xd3, 0xc3, 0xcf, 0x20, 0xc9, 0x30,
	0xce, 0xcf, 0x2d, 0xda, 0x73, 0x0a, 0xc0, 0x46, 0x77, 0x5a, 0x10, 0x34,
	0x30, 0x30, 0x30, 0x30, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x00, 0x59,
	0xfa, 0x5f, 0xc2, 0x47, 0x96, 0xb8, 0xef, 0x1b, 0x0b, 0x58, 0xc8, 0xd9,
	0xc6, 0xb8, 0x63, 0x34, 0xcf, 0x63, 0xff, 0x34, 0x30, 0x30, 0x30, 0x30,
	0x20, 0x64, 0x62, 0x00, 0xc3, 0x58, 0x8d, 0xeb, 0x65, 0x07, 0x95, 0x3f,
	0xcb, 0xa3, 0xd5, 0x69, 0x3f, 0x45, 0x12, 0xd2, 0x81, 0x3f, 0x57, 0x72,
	0x34, 0x30, 0x30, 0x30, 0x30, 0x20, 0x67, 0x69, 0x74, 0x00, 0xc1, 0xfe,
	0x5b, 0x37, 0x39, 0xf3, 0x19, 0x26, 0xdc, 0xc3, 0x1d, 0xf5, 0xcf, 0x3c,
	0x79, 0xe5, 0xd0, 0x9a, 0x89, 0xec, 0x31, 0x30, 0x30, 0x36, 0x34, 0x34,
	0x20, 0x67, 0x69, 0x74, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x2e, 0x74, 0x65,
	0x78, 0x00, 0xc2, 0xb4, 0xf9, 0x3c, 0x09, 0x27, 0x32, 0x0f, 0x4a, 0x13,
	0xa3, 0x0b, 0x8f, 0x6c, 0x1d, 0xd8, 0xb4, 0x14, 0xf5, 0x7e, 0x34, 0x30,
	0x30, 0x30, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x73, 0x00, 0xf0, 0x49, 0x58,
	0x6d, 0xcb, 0x75, 0xd7, 0x92, 0x3c, 0x0e, 0x86, 0x11, 0x1d, 0xfa, 0xde,
	0xf9, 0xe6, 0x88, 0xaa, 0xbf, 0x31, 0x30, 0x30, 0x36, 0x34, 0x34, 0x20,
	0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x67, 0x6f, 0x00, 0x5c, 0x95, 0x4c, 0x27,
	0x9c, 0x0f, 0xcf, 0xfe, 0xf4, 0xbb, 0x8e, 0xb4, 0x0d, 0x2a, 0xd8, 0xd7,
	0xcf, 0xfa, 0x2b, 0xcf, 0x34, 0x30, 0x30, 0x30, 0x30, 0x20, 0x72, 0x65,
	0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x00, 0x11, 0xf8, 0xbf,
	0x81, 0x1f, 0xba, 0x24, 0xcf, 0xe3, 0xb8, 0xa2, 0x1a, 0x71, 0xf1, 0x55,
	0x90, 0xd6, 0x04, 0x3b, 0x6e, 0x34, 0x30, 0x30, 0x30, 0x30, 0x20, 0x72,
	0x6f, 0x75, 0x74, 0x65, 0x72, 0x00, 0x4d, 0x41, 0x5b, 0x78, 0xbc, 0x70,
	0x52, 0x53, 0x28, 0x78, 0x9c, 0x51, 0x8c, 0xdf, 0x0f, 0xc2, 0xeb, 0x28,
	0x2c, 0xc3, 0x34, 0x30, 0x30, 0x30, 0x30, 0x20, 0x73, 0x65, 0x72, 0x76,
	0x65, 0x72, 0x00, 0x1f, 0x05, 0xb8, 0x5f, 0x11, 0x86, 0x6a, 0x4a, 0x8e,
	0xb2, 0x4f, 0x4e, 0x9a, 0xbf, 0x46, 0x9a, 0xf5, 0xc4, 0x9a, 0x71, 0x34,
	0x30, 0x30, 0x30, 0x30, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63,
	0x74, 0x69, 0x6f, 0x6e, 0x00, 0x97, 0x3a, 0xf6, 0x77, 0xec, 0x6b, 0xda,
	0x21, 0x03, 0xe0, 0x0b, 0xe1, 0x31, 0xb4, 0xd4, 0x14, 0x21, 0xb0, 0x18,
	0x08, 0x34, 0x30, 0x30, 0x30, 0x30, 0x20, 0x74, 0x79, 0x70, 0x65, 0x73,
	0x00, 0xe0, 0x76, 0x40, 0xcd, 0xef, 0xde, 0xb2, 0x7c, 0xdd, 0xa1, 0x68,
	0xc0, 0x8b, 0x41, 0xfd, 0x47, 0x19, 0x73, 0x1b, 0x5a, 0x34, 0x30, 0x30,
	0x30, 0x30, 0x20, 0x75, 0x69, 0x00, 0x5f, 0xfd, 0xad, 0x79, 0x9d, 0xfc,
	0xcb, 0x1c, 0xe4, 0x44, 0x9c, 0x29, 0x9d, 0x58, 0xfb, 0x4b, 0xf0, 0xd4,
	0x74, 0xa5, 0x34, 0x30, 0x30, 0x30, 0x30, 0x20, 0x75, 0x74, 0x69, 0x6c,
	0x00, 0x88, 0xf9, 0x0c, 0x42, 0x8d, 0x35, 0x25, 0x42, 0x5e, 0x2a, 0x59,
	0x3f, 0x24, 0xcc, 0x43, 0xf9, 0x81, 0x66, 0xfc, 0x71,
}

var fixtureTreeEntries = []treeEntry{
	treeEntry{Mode: "100644", File: ".gitignore", Hash: hashFromString("037f24bcd0f294331e58b3dc4da8a9b3c5369149")},
	treeEntry{Mode: "100644", File: "Godeps", Hash: hashFromString("fdee6db672c2401b6e027fc5f62f4371c51a2726")},
	treeEntry{Mode: "100644", File: "HACKING.md", Hash: hashFromString("a0858e680db668de82635eb48690d7933da02814")},
	treeEntry{Mode: "100644", File: "LICENSE", Hash: hashFromString("215701c66d8623c0b66f1bb4a78fe5f4e1d5e03a")},
	treeEntry{Mode: "100644", File: "Makefile", Hash: hashFromString("292581f3097aa43eef249e3bf5f11dddf4d90d29")},
	treeEntry{Mode: "100644", File: "README.md", Hash: hashFromString("ec6e47d3c3cf20c930cecf2dda730ac046775a10")},
	treeEntry{Mode: "40000", File: "block", Hash: hashFromString("59fa5fc24796b8ef1b0b58c8d9c6b86334cf63ff")},
	treeEntry{Mode: "40000", File: "db", Hash: hashFromString("c3588deb6507953fcba3d5693f4512d2813f5772")},
	treeEntry{Mode: "40000", File: "git", Hash: hashFromString("c1fe5b3739f31926dcc31df5cf3c79e5d09a89ec")},
	treeEntry{Mode: "100644", File: "gitchain.tex", Hash: hashFromString("c2b4f93c0927320f4a13a30b8f6c1dd8b414f57e")},
	treeEntry{Mode: "40000", File: "keys", Hash: hashFromString("f049586dcb75d7923c0e86111dfadef9e688aabf")},
	treeEntry{Mode: "100644", File: "main.go", Hash: hashFromString("5c954c279c0fcffef4bb8eb40d2ad8d7cffa2bcf")},
	treeEntry{Mode: "40000", File: "repository", Hash: hashFromString("11f8bf811fba24cfe3b8a21a71f15590d6043b6e")},
	treeEntry{Mode: "40000", File: "router", Hash: hashFromString("4d415b78bc70525328789c518cdf0fc2eb282cc3")},
	treeEntry{Mode: "40000", File: "server", Hash: hashFromString("1f05b85f11866a4a8eb24f4e9abf469af5c49a71")},
	treeEntry{Mode: "40000", File: "transaction", Hash: hashFromString("973af677ec6bda2103e00be131b4d41421b01808")},
	treeEntry{Mode: "40000", File: "types", Hash: hashFromString("e07640cdefdeb27cdda168c08b41fd4719731b5a")},
	treeEntry{Mode: "40000", File: "ui", Hash: hashFromString("5ffdad799dfccb1ce4449c299d58fb4bf0d474a5")},
	treeEntry{Mode: "40000", File: "util", Hash: hashFromString("88f90c428d3525425e2a593f24cc43f98166fc71")},
}

func TestTreeDecode(t *testing.T) {
	c := &Tree{}
	err := c.SetBytes(fixtureTree[9:]) // skip the header
	if err != nil {
		t.Errorf("%v", err)
		return
	}
	for i := range fixtureTreeEntries {
		assert.Equal(t, c.Entries[i], fixtureTreeEntries[i])
	}
}

func TestTreeDecodeCompressed(t *testing.T) {
	c := &Tree{}
	var b bytes.Buffer
	w := zlib.NewWriter(&b)
	w.Write(fixtureTree[9:]) // skip the header
	w.Close()
	err := c.SetBytes(b.Bytes())
	if err != nil {
		t.Errorf("%v", err)
		return
	}
	assert.True(t, bytes.Compare(c.Bytes(), fixtureTree[9:]) == 0)
	for i := range fixtureTreeEntries {
		assert.Equal(t, c.Entries[i], fixtureTreeEntries[i])
	}
}

func hashFromString(h string) []byte {
	b, err := hex.DecodeString(h)
	if err != nil {
		return nil
	}
	return b
}
